package domain.shop;

import application.WicketApplication;
import domain.AbstractEntity;
import domain.Comment;
import domain.ImageEntry;
import domain.cms.CmsAttribute;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Index;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.Store;
import service.ConfigurationService;

import javax.persistence.*;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlTransient;
import java.math.BigDecimal;
import java.util.*;

@Entity
@Indexed
public class Product extends AbstractEntity implements Comparable {

    private static final String productPrefix = "Product/";
    private static final String imagePrefix = "resource/images/imageEntryId/";
    private String url = "";
    private String imgUrl = "";
    @OneToOne
    @Cascade(CascadeType.ALL)
    private CmsAttribute cmsAttribute = new CmsAttribute();
    @ManyToOne
    private Manufacturer manufacturer;
    @ManyToMany(mappedBy = "products")
    private Set<Category> categories = new HashSet<Category>();
    @OneToMany(mappedBy = "product")
    @Cascade(CascadeType.ALL)
    private List<Attribute> attributes = new ArrayList<Attribute>();
    /**
     * Components of this products
     */

    private BigDecimal price;
    /**
     * How many products was sold.
     */
    private Integer sold = 0;
    @Field
    @Temporal(javax.persistence.TemporalType.DATE)
    private Date insertedDate;
    private boolean enabled;
    @Field(index = Index.TOKENIZED, store = Store.YES)
    private String name = "";
    private String carType = "";
    @OneToMany(mappedBy = "product")
    private List<Comment> comments = new ArrayList<Comment>();
    @OneToMany
    private List<ImageEntry> images = new ArrayList<ImageEntry>();
    @OneToOne
    private ImageEntry mainImage;

    @ManyToMany
    @JoinTable(
            name = "PRODUCT_DEPENDENCIES",
            joinColumns = @JoinColumn(name = "PRODUCT_ID", referencedColumnName = "ID"),
            inverseJoinColumns = @JoinColumn(name = "DEPENDENCY_ID", referencedColumnName = "ID")
    )
    private Set<Product> relatedProducts = new HashSet<Product>();
//    @ManyToMany(mappedBy = "relatedProducts")
//    private Set<Product> relatedTo = new HashSet<Product>();

    @ManyToMany
    @JoinTable(name = "components")
    private Set<Product> components = new HashSet<Product>();
    @ManyToMany(mappedBy = "components")
    private Set<Product> componentTo = new HashSet<Product>();

    public Set<Product> getComponentTo() {
        return componentTo;
    }

    public Product() {
    }

    public Product(String string) {
        cmsAttribute.setTitle(string);
    }

//    public Set<Product> getRelatedTo() {
//        return relatedTo;
//    }
//
//    public void setRelatedTo(Set<Product> relatedTo) {
//        this.relatedTo = relatedTo;
//    }

    @XmlElement(name = "IMGURL")
    public String getImgUrl() {
        if (this.mainImage != null) {
            String domainName = ((ConfigurationService) WicketApplication.getInstance().
                    getBean("configurationService")).getConfig().getDomainName();
            imgUrl = domainName + imagePrefix + mainImage.getId();
        }
        return imgUrl;
    }

    public void setImgUrl(String imgUrl) {
        this.imgUrl = imgUrl;
    }

    @XmlElement(name = "URL")
    public String getUrl() {
        String domainName = ((ConfigurationService) WicketApplication.getInstance().
                getBean("configurationService")).getConfig().getDomainName();
        url = domainName + productPrefix + this.getId();
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    @XmlTransient
    public String getCarType() {
        return carType;
    }

    public void setCarType(String carType) {
        this.carType = carType;
    }

    @XmlTransient
    public Set<Product> getRelatedProducts() {
        Set foo = new HashSet<Product>();

        if (relatedProducts.size() != 0) {
            foo.addAll(relatedProducts);
        }
//        if (relatedTo.size() != 0) {
//
//            foo.addAll(relatedTo);
//        }
        return foo;
    }

    @XmlTransient
    public List<ImageEntry> getImages() {
        return images;
    }

    public void setImages(List<ImageEntry> images) {
        this.images = images;
    }

    @XmlTransient
    public ImageEntry getMainImage() {
        return mainImage;
    }

    public void setMainImage(ImageEntry mainImage) {
        this.mainImage = mainImage;
    }

    @XmlElement(name = "PRODUCT")
    public String getName() {
        name = cmsAttribute.getTitle();
        return name;
    }

    public void setName(String name) {
        this.name = name;
        this.cmsAttribute.setTitle(name);
    }

    @XmlTransient
    public CmsAttribute getCmsAttribute() {
        return cmsAttribute;
    }

    public void setCmsAttribute(CmsAttribute cmsAttribute) {
        this.cmsAttribute = cmsAttribute;
    }

    @XmlTransient
    public List<Attribute> getAttributes() {
        return attributes;
    }

    public void setAttributes(List<Attribute> attributes) {
        this.attributes = attributes;
    }

    public boolean addAttribute(Attribute e) {
        return attributes.add(e);
    }

    public boolean removeAttribute(Attribute o) {
        return attributes.remove(o);
    }

    @XmlTransient
    public Set<Category> getCategories() {
        return categories;
    }


    @XmlTransient
    public Set<Product> getComponents() {
        return components;
    }


    @XmlTransient
    public boolean isEnabled() {
        return enabled;
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    @XmlTransient
    public Date getInsertedDate() {
        return insertedDate;
    }

    public void setInsertedDate(Date insertedDate) {
        this.insertedDate = insertedDate;
    }

    @XmlTransient
    public Manufacturer getManufacturer() {
        return manufacturer;
    }

    public void setManufacturer(Manufacturer manufacturer) {
        this.manufacturer = manufacturer;
    }

    @XmlElement(name = "PRICE_VAT")
    public BigDecimal getPrice() {
        return price;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }

    @XmlTransient
    public Integer getSold() {
        return sold;
    }

    public void setSold(Integer sold) {
        this.sold = sold;
    }

    /**
     * Increase sold field by 1.
     */
    public void increaseSold() {
        this.sold++;
    }

    public void setTitle(String title) {
        cmsAttribute.setTitle(title);
    }

    public void setKeywords(String keywords) {
        cmsAttribute.setKeywords(keywords);
    }

    public void setDescription(String description) {
        cmsAttribute.setDescription(description);
    }

    public void setContent(String content) {
        cmsAttribute.setContent(content);
    }

    @XmlTransient
    public String getTitle() {
        return cmsAttribute.getTitle();
    }

    @XmlTransient
    public java.util.Date getLastEditedDate() {
        return cmsAttribute.getLastEditedDate();
    }

    @XmlTransient
    public String getKeywords() {
        return cmsAttribute.getKeywords();
    }

    @XmlTransient
    public String getDescription() {
        return cmsAttribute.getDescription();
    }

    @XmlElement(name = "DESCRIPTION")
    public String getContent() {
        return cmsAttribute.getContent();
    }

    @XmlTransient
    public String getShortContent() {
        return cmsAttribute.getShortContent();
    }

    public void setShortContent(String shortContent) {
        cmsAttribute.setShortContent(shortContent);
    }

    @XmlTransient
    public List<Comment> getComments() {
        return comments;
    }

    public void setComments(List<Comment> comments) {
        this.comments = comments;
    }

    public void addCategory(Category category) {
        getCategories().add(category);
    }

    public void removeCategory(Category category) {
        getCategories().remove(category);
    }

    public int compareTo(Object o) {
        if (!(o instanceof Product)) {
            throw new ClassCastException("A Product object expected.");
        }
        if (((Product) o).getId() == null) {
            throw new IllegalStateException("A Product is not persisted or/and does not have ID.");
        }
        Long newId = ((Product) o).getId();
        return (int) (this.getId() - newId);
    }

    public void addRelatedProduct(Product p) {
        if (!this.getId().equals(p.getId()))
            this.relatedProducts.add(p);
    }

    public void addComponentProduct(Product p) {
        if (!this.getId().equals(p.getId()))
            this.components.add(p);
    }

    public boolean removeRelatedProduct(Product p) {
        return this.relatedProducts.remove(p);
    }

    public void addComponentToProduct(Product p) {
        if (!this.getId().equals(p.getId()))
            this.componentTo.add(p);
    }


    public boolean removeComponentToProduct(Product p) {
        return this.componentTo.remove(p);
    }

    public boolean removeComponentProduct(Product p) {
        return this.components.remove(p);
    }

    @Override
    public String toString() {
        return "Product = \"" + getTitle() + " Id " + getId() + "\"";
    }

    public void addImage(ImageEntry image) {
        this.images.add(image);
    }
}

